from typing import List, Tuple, Optional, Dict
from chess.board import Board
from chess.pieces import Piece, King, Queen, Rook, Bishop, Knight, Pawn

class Game:
    def __init__(self):
        """
        初始化游戏
        创建棋盘并设置游戏状态
        """
        self.board = Board()  # 创建棋盘
        self.current_player = 'white'  # 白方先行
        self.game_over = False  # 游戏是否结束
        self.winner = None  # 胜者
        self.draw = False  # 是否和棋
        self.check = False  # 是否将军
        self.checkmate = False  # 是否将死
        self.stalemate = False  # 是否逼和
        self.selected_piece = None  # 当前选中的棋子
        self.valid_moves = []  # 当前选中棋子的有效移动位置
        self.move_history = []  # 移动历史
        
        # 用于王车易位的检查
        self.white_king_moved = False
        self.black_king_moved = False
        self.white_rooks_moved = {0: False, 7: False}  # 列号：是否移动
        self.black_rooks_moved = {0: False, 7: False}
    
    def select_piece(self, position: Tuple[int, int]) -> bool:
        """
        选择棋子
        :param position: 要选择的棋子位置
        :return: 如果选择成功返回True，否则返回False
        """
        piece = self.board.get_piece_at(position)
        
        # 检查是否有棋子，以及棋子颜色是否匹配当前玩家，以及游戏是否结束
        if piece is None:
            # print(f"位置{position}没有棋子")
            return False
        
        if piece.color != self.current_player and not self._is_checking_legal_moves():
            # print(f"棋子颜色{piece.color}与当前玩家{self.current_player}不匹配")
            return False
        
        if self.game_over and not self._is_checking_legal_moves():
            # print("游戏已结束")
            return False
        
        # 计算有效移动
        raw_moves = piece.get_possible_moves(self.board)
        valid_moves = []
        
        # 调试信息
        # print(f"棋子{type(piece).__name__}在{position}的原始可能移动: {raw_moves}")
        
        # 检查每个移动是否会导致自己被将军
        for move in raw_moves:
            # 模拟移动
            original_target = self.board.get_piece_at(move)
            self.board.remove_piece_at(move)
            original_position = piece.position
            original_has_moved = piece.has_moved
            
            # 临时移动棋子
            self.board.remove_piece_at(original_position)
            piece.position = move
            self.board.place_piece(piece)
            
            # 检查移动后是否仍被将军
            # 检查棋子本方的国王是否被将军
            king_in_check = self.board.is_king_in_check(piece.color)
            
            # 恢复棋盘状态
            self.board.remove_piece_at(move)
            piece.position = original_position
            piece.has_moved = original_has_moved
            self.board.place_piece(piece)
            
            if original_target:
                self.board.place_piece(original_target)
            
            # 如果移动后不会被将军，则添加到有效移动列表
            if not king_in_check:
                valid_moves.append(move)
        
        # 处理王车易位
        if isinstance(piece, King) and not piece.has_moved and not self.board.is_king_in_check(piece.color):
            # 检查短易位（王翼易位）
            can_castle_short = self._can_castle_short(piece.color)
            if can_castle_short:
                if piece.color == 'white':
                    valid_moves.append((7, 6))  # 白王短易位目标位置
                else:
                    valid_moves.append((0, 6))  # 黑王短易位目标位置
            
            # 检查长易位（后翼易位）
            can_castle_long = self._can_castle_long(piece.color)
            if can_castle_long:
                if piece.color == 'white':
                    valid_moves.append((7, 2))  # 白王长易位目标位置
                else:
                    valid_moves.append((0, 2))  # 黑王长易位目标位置
        
        self.selected_piece = piece
        self.valid_moves = valid_moves
        
        # 调试信息
        # print(f"棋子{type(piece).__name__}在{position}的有效移动: {valid_moves}")
        
        return len(valid_moves) > 0
    
    def _is_checking_legal_moves(self) -> bool:
        """
        检查当前是否在检查合法移动（用于区分游戏玩家手动选择和AI/系统检查合法移动）
        """
        # 获取调用栈
        import inspect
        stack = inspect.stack()
        # 如果调用来自_update_game_state方法，则认为是在检查合法移动
        for frame in stack:
            if frame.function == '_update_game_state':
                return True
        return False
    
    def _can_castle_short(self, color: str) -> bool:
        """
        检查是否可以进行短易位（王翼易位）
        :param color: 棋子颜色
        :return: 如果可以进行短易位返回True，否则返回False
        """
        # 检查国王和车是否移动过
        if color == 'white':
            if self.white_king_moved or self.white_rooks_moved.get(7, True):
                return False
            king_row, king_col = 7, 4
            rook_pos = (7, 7)
        else:
            if self.black_king_moved or self.black_rooks_moved.get(7, True):
                return False
            king_row, king_col = 0, 4
            rook_pos = (0, 7)
        
        # 检查王和车之间是否有棋子
        for col in range(king_col + 1, 7):
            if self.board.get_piece_at((king_row, col)) is not None:
                return False
        
        # 检查国王经过的位置是否被攻击
        opponent = 'black' if color == 'white' else 'white'
        for col in range(king_col, king_col + 3):
            if self.board.is_square_under_attack((king_row, col), opponent):
                return False
        
        return True
    
    def _can_castle_long(self, color: str) -> bool:
        """
        检查是否可以进行长易位（后翼易位）
        :param color: 棋子颜色
        :return: 如果可以进行长易位返回True，否则返回False
        """
        # 检查国王和车是否移动过
        if color == 'white':
            if self.white_king_moved or self.white_rooks_moved.get(0, True):
                return False
            king_row, king_col = 7, 4
            rook_pos = (7, 0)
        else:
            if self.black_king_moved or self.black_rooks_moved.get(0, True):
                return False
            king_row, king_col = 0, 4
            rook_pos = (0, 0)
        
        # 检查王和车之间是否有棋子
        for col in range(1, king_col):
            if self.board.get_piece_at((king_row, col)) is not None:
                return False
        
        # 检查国王经过的位置是否被攻击
        opponent = 'black' if color == 'white' else 'white'
        for col in range(king_col - 2, king_col + 1):
            if self.board.is_square_under_attack((king_row, col), opponent):
                return False
        
        return True
    
    def move_piece(self, to_position: Tuple[int, int]) -> bool:
        """
        移动选中的棋子到目标位置
        :param to_position: 目标位置
        :return: 如果移动成功返回True，否则返回False
        """
        if self.selected_piece is None or to_position not in self.valid_moves or self.game_over:
            return False
        
        from_position = self.selected_piece.position
        piece = self.selected_piece
        
        # 保存移动前的状态（用于记录历史）
        move_record = {
            'piece': piece,
            'from': from_position,
            'to': to_position,
            'captured': self.board.get_piece_at(to_position),
            'en_passant': False,
            'castle': False,
            'promotion': False
        }
        
        # 处理王车易位
        if isinstance(piece, King) and abs(from_position[1] - to_position[1]) > 1:
            self._handle_castling(piece, from_position, to_position)
            move_record['castle'] = True
        else:
            # 正常移动
            self.board.move_piece(from_position, to_position)
        
        # 更新王车易位的状态跟踪
        if isinstance(piece, King):
            if piece.color == 'white':
                self.white_king_moved = True
            else:
                self.black_king_moved = True
        elif isinstance(piece, Rook):
            row, col = from_position
            if piece.color == 'white' and row == 7:
                self.white_rooks_moved[col] = True
            elif piece.color == 'black' and row == 0:
                self.black_rooks_moved[col] = True
        
        # 处理吃过路兵
        if isinstance(piece, Pawn) and from_position[1] != to_position[1] and move_record['captured'] is None:
            # 这是一个斜向移动到空位置，说明是吃过路兵
            en_passant_pos = (from_position[0], to_position[1])
            move_record['en_passant'] = True
            move_record['captured'] = self.board.get_piece_at(en_passant_pos)
        
        # 处理兵升变（默认升变为皇后）
        if isinstance(piece, Pawn) and (to_position[0] == 0 or to_position[0] == 7):
            self._promote_pawn(to_position, 'queen')
            move_record['promotion'] = 'queen'
        
        # 记录移动历史
        self.move_history.append(move_record)
        
        # 切换玩家
        self.current_player = 'black' if self.current_player == 'white' else 'white'
        
        # 更新游戏状态 (必须在切换玩家后更新)
        self._update_game_state()
        
        # 清除选择状态
        self.selected_piece = None
        self.valid_moves = []
        
        return True
    
    def _handle_castling(self, king: King, from_pos: Tuple[int, int], to_pos: Tuple[int, int]):
        """
        处理王车易位
        :param king: 国王棋子
        :param from_pos: 国王起始位置
        :param to_pos: 国王目标位置
        """
        king_row, king_from_col = from_pos
        _, king_to_col = to_pos
        
        # 移动国王
        self.board.move_piece(from_pos, to_pos)
        
        # 移动车
        if king_to_col == 6:  # 短易位（王翼易位）
            rook_from_col = 7
            rook_to_col = 5
        else:  # 长易位（后翼易位）
            rook_from_col = 0
            rook_to_col = 3
        
        rook_from_pos = (king_row, rook_from_col)
        rook_to_pos = (king_row, rook_to_col)
        self.board.move_piece(rook_from_pos, rook_to_pos)
    
    def _promote_pawn(self, position: Tuple[int, int], promotion_type: str):
        """
        将兵升变为其他棋子
        :param position: 兵的位置
        :param promotion_type: 升变类型 ('queen', 'rook', 'bishop', 'knight')
        """
        pawn = self.board.get_piece_at(position)
        if not isinstance(pawn, Pawn):
            return
        
        # 创建新棋子
        color = pawn.color
        new_piece = None
        
        if promotion_type == 'queen':
            new_piece = Queen(color, position)
        elif promotion_type == 'rook':
            new_piece = Rook(color, position)
        elif promotion_type == 'bishop':
            new_piece = Bishop(color, position)
        elif promotion_type == 'knight':
            new_piece = Knight(color, position)
        
        if new_piece:
            # 替换兵
            self.board.remove_piece_at(position)
            self.board.place_piece(new_piece)
    
    def _update_game_state(self):
        """
        更新游戏状态
        检查将军、将死、逼和等状态
        """
        next_player = 'black' if self.current_player == 'white' else 'white'
        
        # 检查将军状态
        self.check = self.board.is_king_in_check(next_player)
        
        # 检查是否有合法移动
        has_legal_moves = False
        
        # 获取下一个玩家的所有棋子
        next_player_pieces = self.board.get_all_pieces(next_player)
        
        # 调试信息
        print(f"检查{next_player}方是否有合法移动，共有{len(next_player_pieces)}个棋子")
        
        # 为每个棋子检查是否有合法移动
        for piece in next_player_pieces:
            # 保存当前选择状态
            old_selected = self.selected_piece
            old_valid_moves = self.valid_moves.copy() if self.valid_moves else []
            
            # 尝试选择这个棋子，看它是否有合法移动
            if self.select_piece(piece.position):
                has_legal_moves = True
                print(f"棋子{type(piece).__name__}在{piece.position}有{len(self.valid_moves)}个合法移动")
                
                # 恢复之前的选择状态
                self.selected_piece = old_selected
                self.valid_moves = old_valid_moves
                break
            else:
                print(f"棋子{type(piece).__name__}在{piece.position}没有合法移动")
        
        # 重置选择状态
        self.selected_piece = None
        self.valid_moves = []
        
        # 判断将死或逼和
        if not has_legal_moves:
            print(f"{next_player}方没有合法移动")
            if self.check:
                print(f"{next_player}方被将军，判定为将死")
                self.checkmate = True
                self.game_over = True
                self.winner = self.current_player
            else:
                print(f"{next_player}方没有被将军，判定为逼和")
                self.stalemate = True
                self.game_over = True
                self.draw = True
        else:
            # 确保游戏继续
            self.game_over = False
            self.checkmate = False
            self.stalemate = False
    
    def reset_game(self):
        """
        重置游戏状态
        """
        self.board = Board()
        self.current_player = 'white'
        self.game_over = False
        self.winner = None
        self.draw = False
        self.check = False
        self.checkmate = False
        self.stalemate = False
        self.selected_piece = None
        self.valid_moves = []
        self.move_history = []
        self.white_king_moved = False
        self.black_king_moved = False
        self.white_rooks_moved = {0: False, 7: False}
        self.black_rooks_moved = {0: False, 7: False}
    
    def get_game_state(self) -> Dict:
        """
        获取当前游戏状态
        :return: 游戏状态字典
        """
        return {
            'current_player': self.current_player,
            'game_over': self.game_over,
            'winner': self.winner,
            'draw': self.draw,
            'check': self.check,
            'checkmate': self.checkmate,
            'stalemate': self.stalemate
        } 